package com.lsk.netdisk.auth.authc;


import com.lsk.netdisk.auth.helpers.UserHelper;
import com.lsk.netdisk.auth.mail.MyMailSender;
import com.lsk.netdisk.auth.mappers.UserMapper;
import com.lsk.netdisk.auth.model.User;
import com.lsk.netdisk.auth.util.HashUtil;
import com.lsk.netdisk.auth.util.SpringUtil;
import com.lsk.netdisk.auth.util.StringUtil;
import com.lsk.netdisk.common.redis.core.RedisComponent;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
import java.util.UUID;

@Slf4j
public class Authc {
	private static UserMapper mapper = SpringUtil.getBean(UserMapper.class);
	private static MyMailSender mailSender = SpringUtil.getBean(MyMailSender.class);
	private static RedisComponent redis = SpringUtil.getBean("redisComponent",RedisComponent.class);

	public static LoginResult login(String token,String password,String username){
		if (StringUtil.isEmpty(token,password,username)){
			return new LoginResult(false,"Token or password or username is empty.");
		}
		User user = mapper.queryUserByName(username);
		if (user == null){
			return new LoginResult(false,"User not found.");
		}
		if (!(user.getState() == 1)){
			return new LoginResult(false,"User is disabled");
		}
		if (!(user.getPassword().equals(password))){
			return new LoginResult(false,"Password is wrong.");
		}
		Token.UserStatePair state = new Token.UserStatePair(token,State.Login);
		redis.set(token+"-STATE",state,0);
		redis.set(token+"-UID",user.getId().toString(),0);
		return new LoginResult(true,"");
	}

	public static String register(String username,String password,String email,String token){
		User user = new User();
		user.setName(username);
		user.setPassword(password);
		user.setEmail(email);
		user.setState(0);
		user.setRole("user");
		mapper.addUser(user);
		String registerCode = UUID.randomUUID().toString();
		System.out.println(registerCode);
		redis.set(token+"-REG-CODE",registerCode,120000);
		Integer id = mapper.queryUserByName(username).getId();
		redis.set(token+"-UID",id,0);
		mailSender.sendRegisterCode(email,registerCode);
		return registerCode;
	}
	public static void doneRegister(String token,String regCode) {
		String localRegCode = redis.get(token + "-REG-CODE", String.class);
		if (StringUtil.isEmpty(localRegCode, regCode)) {
			throw new RuntimeException("regcode is empty");
		}
		if (!localRegCode.equals(regCode)) {
			throw new RuntimeException(("regcode is wrong."));
		}
		Integer id = Integer.parseInt(redis.rawGet(token + "-UID"));
		mapper.enableUser(id);
		redis.set(token+"-STATE",new Token.UserStatePair(token,State.Login),0);
		redis.delete(token+"-REG-CODE");
	}
	public static void logout(String token){
		redis.set(token+"-STATE",new Token.UserStatePair(token,State.Guest),0);
		redis.delete(token+"-UID");
	}
	public static User getCurrentUser(String token){
		Integer uid = redis.get(token+"-UID",Integer.class);
		User user = mapper.queryUserById(uid);
		return user;
	}
	public static boolean isUserLogined(String token){
		State state = redis.get(token+"-STATE", Token.UserStatePair.class).getState();
		if(state.equals(State.Login)){
			return true;
		}else{
			return false;
		}
	}
	private static State stringToState(String state){
		log.info(state);
		switch (state){
			case "Login":
				return State.Login;
			default:
				return State.Guest;
		}
	}
	public static String getUID(String token){
		Integer uid = redis.get(token+"-UID",Integer.class);
		return uid.toString();
	}
	public static void resendRegisterEmail(String token){
		String registerCode = redis.get(token+"-REG-CODE",String.class);
		User user = getCurrentUser(token);
		String mail = user.getEmail();
		mailSender.sendRegisterCode(mail,registerCode);
	}
	public static void sendRePasswordMail(String token, String addr){
		try {
			redis.set(token+"-MAIL-ADDRESS",addr,86400);
			String rePasswordToken = UUID.randomUUID().toString();
			String hash = HashUtil.sha256String(rePasswordToken);
			redis.set(addr + "-REPASS-TOKEN", rePasswordToken, 86400);
			String url = "http://localhost:10008/findbackPassword?repassToken=" + hash;
			mailSender.sendRePasswordURL(addr, url);
		}catch (Exception e){
			throw new RuntimeException(e);
		}
	}
	public static void findbackPassword(String token, String rePasswordToken, String newPassword){
		String mailAddr = redis.get(token+"-MAIL-ADDRESS",String.class);
		String redisRePasswordToken = HashUtil.sha256String(redis.get(mailAddr+"-REPASS-TOKEN",String.class));
		if(!redisRePasswordToken.equals(redisRePasswordToken)){
			throw new RuntimeException("Token does not match.");
		}
		User user = mapper.queryUserByEmail(mailAddr);
		user.setPassword(newPassword);
		mapper.updateUser(user);
		login(token,user.getPassword(),user.getName());
	}
	public static String createVerifyCode(){
		String captchaID = UUID.randomUUID().toString();
		BufferedImage image = new BufferedImage(100,30,BufferedImage.TYPE_INT_RGB);
		Graphics graphics = image.getGraphics();
		graphics.setColor(new Color(180,180,180));
		graphics.fillRect(0,0,100,30);
		char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456".toCharArray();
		Random random = new Random();
		String captcha = "";
		for (int i = 0; i < 4; i++){
			int index = random.nextInt(chars.length);
			graphics.setColor(new Color(random.nextInt(150), random.nextInt(200), random.nextInt(255)));
			graphics.drawString(chars[index] + "",(i * 20) + 15, 20);
			captcha += chars[index];
		}
		redis.set("CAPTCHA-"+captchaID,captcha,60000);
		try{
			FileOutputStream fos = new FileOutputStream("D://tmp/"+captchaID+".jpg");
			ImageIO.write(image,"JPG",fos);
		}catch (IOException ioe){
			log.error("Create CAPTCHA failed: ",ioe);
			throw new RuntimeException(ioe);
		}
		return captchaID;
	}
	public static boolean checkCAPTCHA(String id, String word){
		String redisCAPTCHA = redis.get("CAPTCHA-"+id, String.class);
		if (redisCAPTCHA == null || redisCAPTCHA.equals("")){
			throw new RuntimeException("CAPTCHA "+id+" not found!");
		}
		boolean result = redisCAPTCHA.equals(word);
		redis.delete("CAPTCHA-"+id);
		return result;
	}
	@Data
	@NoArgsConstructor
	@AllArgsConstructor
	public static class LoginResult{
		private boolean isSuccess;
		private String message;
	}
}
